package com.xpec.c4.service.module.datacenter.player;

import java.math.BigDecimal;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ms.game.bank.BankMoneyChangeWay;
import com.ms.game.bank.db.BankLogModel;
import com.ms.game.characterInfo.CharacterInfoProcessor;
import com.ms.game.characterInfo.db.CharacterInfoLogDAO;
import com.ms.game.itembox.GameDropItemParam;
import com.ms.game.slot.base.GainRateSystem;
import com.ms.service.error.ErrorCode;
import com.xpec.c4.db.model.log.basic.BasicLogModel;
import com.xpec.c4.game.character.PlayerManager;
import com.xpec.c4.game.common.Helper;
import com.xpec.c4.game.datamanager.ResultNo;
import com.xpec.c4.game.datamanager.agent.money.ChangeCoin;
import com.xpec.c4.game.datamanager.agent.money.ChangeCoinLister;
import com.xpec.c4.game.datamanager.agent.money.CoinType;
import com.xpec.c4.game.datamanager.agent.money.MoneyChangeParam;
import com.xpec.c4.game.datamanager.agent.money.MoneyChangeWay;
import com.xpec.c4.service.module.BasicServiceModule;
import com.xpec.c4.service.module.ServerProperties;
import com.xpec.c4.service.module.datacenter.DCAsyncCommand;
import com.xpec.c4.service.module.datacenter.player.db.DailyExchangeLogModel;
import com.xpec.c4.service.module.datacenter.player.db.PlayerMoneyChangeLogModel;

/**
 * 更新玩家金錢的異步處理 task
 * 
 * @author TW15010
 */
public class UpdatePlayerMoneyAsync extends DCAsyncCommand {
	private static final Log log = LogFactory.getLog(UpdatePlayerMoneyAsync.class);

	PlayerDataManager playerDataManager;
	BasicServiceModule currentModule;
	

	@Override
	public void asyncExecute() {
		MoneyChangeParam param = (MoneyChangeParam) dataInfo.getData();

		try {
			PlayerManager.getInstance().updatePlayerMoneyToDB(null, currentModule, param);
		} catch (RuntimeException e) {
			log.error("cannot update player money: " + param.getPlayerId(), e);
			resultCode = ResultNo.DB_OPERATION_FAILED;
			return;
		}


		if (param.getResult() == ErrorCode.SUCCESS) {
			saveCharacterDaliyLog(param);  //每日押注log更新

			if(param.getChangeWay().isBank()){
				//有銀行處理就作銀行的log save
				saveBankLog(param);
			}
			
			resultCode = ResultNo.OK;
		} else {
			resultCode = ResultNo.DB_OPERATION_FAILED;
		}


		return;
	}

	@Override
	public void execute() {
		MoneyChangeParam param = (MoneyChangeParam) dataInfo.getData();

		// callback
		if (playerDataManager != null) {
			playerDataManager.updatePlayerMoneyToDbCallback(resultCode, dataInfo, srcModuleID);
		}

		UpdatePlayerMoneyAsync.saveUpdatePlayerMoneyLog(currentModule, param);
		saveRecvGameDropItemLog();
		sendMissionCheck();
	}

	public UpdatePlayerMoneyAsync(PlayerDataManager playerDataManager, BasicServiceModule currentModule) {
		super();
		this.playerDataManager = playerDataManager;
		this.currentModule = currentModule;
	}
	
	/**
	 * 寫入玩家金錢異動的 log
	 */
	public static void saveUpdatePlayerMoneyLog(BasicServiceModule currentModule, MoneyChangeParam param) {
		if (currentModule != null) {
			if (param.getResult() == ErrorCode.SUCCESS) {
				// 排除領紅包
				if (param.getChangeWay().isAddHonboToBank()) {
					return;
				}

				// 寫 log
				PlayerMoneyChangeLogModel model = new PlayerMoneyChangeLogModel();
				model.setOrderId(param.getOrderId().toString());
				model.setAccountId(param.getAccountId().toString());
				model.setPlayerId(param.getPlayerId().toString());
				model.setPlayerName(param.getPlayerName());
				model.setUserType(param.getUserType());
				model.setGameId(param.getGameId());
				model.setGameName(param.getGameName());
				model.setGameHallId(param.getGameHallId());
				model.setGameHallName(param.getGameHallName());
				model.setChangeWay(param.getChangeWay().getId());
				model.setChangeWayDesc(param.getChangeWay().getDesc());
				model.setVenderId(param.getVenderId());
				model.setSubVenderId(param.getSubVenderId());

				// 填入各個幣別的結果
				ChangeCoinLister coinLister = param.getChangeCoinLister();
				Iterator<Map.Entry<CoinType, ChangeCoin>> it = coinLister.getListIterator();
				ChangeCoin coinInfo = coinLister.getNextCoin(it);
				while (coinInfo != null) {
					switch (coinInfo.getCoinType()) {
					case TRIAL:
						model.setTrialChangeValue(coinInfo.getChangeValue());
						model.setTrialBeforeChange(coinInfo.getCurrentValue());
						model.setTrialAfterChange(coinInfo.getNewValue());
						break;
					case GOLD:
						model.setGoldChangeValue(coinInfo.getChangeValue());
						model.setGoldBeforeChange(coinInfo.getCurrentValue());
						model.setGoldAfterChange(coinInfo.getNewValue());
						break;
					case LUCKY:
						model.setLuckyChangeValue(coinInfo.getChangeValue());
						model.setLuckyBeforeChange(coinInfo.getCurrentValue());
						model.setLuckyAfterChange(coinInfo.getNewValue());
						break;
					default:
						if (log.isErrorEnabled()) {
							log.error("write player(" + model.getPlayerName() + "|" + model.getPlayerId()
									+ ") money change log, unknow coin type: " + coinInfo.getCoinType().getDesc());
						}
						break;
					} // switch(.....)

					coinInfo = coinLister.getNextCoin(it);
				} // while(......)

				//DbLogManager.saveLog(currentModule, param.getPlayerId(), model);
				
				//2016/01/26 add by robert
				if (ServerProperties.isNeedSaveMoneyChangeLog(model)) {
					currentModule.saveDbLog(model);
				}				
				
				DailyExchangeLogModel dailyExchangeLogModel = CharacterInfoProcessor.convertDailyExchange(model);
				if (dailyExchangeLogModel != null) {
					currentModule.saveDbLog(dailyExchangeLogModel);
				}
				
			} // if (param.getResult() == ErrorCode.SUCCESS)
		} // if (currentModule != null)
	}
	
	/**
	 * 儲存遊戲中獲得道具的 log
	 */
	private void saveRecvGameDropItemLog() {
		MoneyChangeParam param = (MoneyChangeParam) dataInfo.getData();
		if (param.getResult() != ErrorCode.SUCCESS) {
			return;
		}

		GameDropItemParam dropItemParam = param.getDropItemParam();

		if (dropItemParam != null) {
			for (BasicLogModel logModel : dropItemParam.getLogList()) {
				currentModule.saveDbLog(logModel);
			}
		}
	}

	/**
	 * 記錄玩家基本資訊的每日log
	 */
	public static void saveCharacterDaliyLog(MoneyChangeParam param) {
		ChangeCoinLister coinLister = param.getChangeCoinLister();
		Iterator<Map.Entry<CoinType, ChangeCoin>> it = coinLister.getListIterator();
		ChangeCoin coinInfo = coinLister.getNextCoin(it);
		while (coinInfo != null) {
			// 如果是試玩幣不記錄
			if (coinInfo.getCoinType() == CoinType.TRIAL) {
				coinInfo = coinLister.getNextCoin(it);
				continue;
			}

			if (param.getChangeWay().isDailyBet()) {
				CharacterInfoLogDAO.saveOrUpdateCharacterDaily
				(
						param.getPlayerId(),
						param.getAccountId(),
						param.getPlayerName(),
						coinInfo.getChangeValue(),
						BigDecimal.ZERO
				);
			} else if (param.getChangeWay().isDailyScore()) {
				CharacterInfoLogDAO.saveOrUpdateCharacterDaily
				(
						param.getPlayerId(),
						param.getAccountId(),
						param.getPlayerName(),
						BigDecimal.ZERO,
						coinInfo.getChangeValue()
				);
			}

			coinInfo = coinLister.getNextCoin(it);
		}
	}
	
	/**
	 * 銀行變動
	 * 紀錄銀行變動後的log
	 */
	private void saveBankLog(MoneyChangeParam param) {
		
		BankMoneyChangeWay changeWay = null;
		if(param.getChangeWay() == MoneyChangeWay.SUB_BANK_DEPOSIT){
			changeWay = BankMoneyChangeWay.ADD_BANK_DEPOSIT;
		}else if(param.getChangeWay() == MoneyChangeWay.ADD_BANK_GET_CASH){
			changeWay = BankMoneyChangeWay.SUB_BANK_GET_CASH;
		}
		
		BankLogModel logModel = new BankLogModel();
		logModel.setOrderId(param.getOrderId().toString());
		logModel.setAccountId(param.getAccountId().toString());
		logModel.setPlayerId(param.getPlayerId().toString());
		logModel.setPlayerName(param.getPlayerName());
		if(changeWay != null){
			logModel.setChangeWay(changeWay.getId());
			logModel.setChangeWayDesc(changeWay.getDesc());
		}
		
		ChangeCoinLister coinLister = param.getChangeCoinLister();
		ChangeCoin coinInfo = coinLister.getCoinMap().get(CoinType.GOLD);
		BigDecimal changeValue = coinInfo.getChangeValue();
		logModel.setBankGoldChangeValue(changeValue);
		logModel.setBankGoldBeforeChange(param.getBankGoldCoin());
		logModel.setGoldChangeValue(changeValue);
		logModel.setGoldBeforeChange(param.getGoldCoin());
		if(changeWay == BankMoneyChangeWay.ADD_BANK_DEPOSIT){
			logModel.setBankGoldAfterChange(Helper.add(param.getBankGoldCoin(), changeValue));
			logModel.setGoldAfterChange(Helper.sub(param.getGoldCoin(), changeValue));
		} else if(changeWay == BankMoneyChangeWay.SUB_BANK_GET_CASH){
			logModel.setBankGoldAfterChange(Helper.sub(param.getBankGoldCoin(), changeValue));
			logModel.setGoldAfterChange(Helper.add(param.getGoldCoin(), changeValue));
		}
		//DbLogManager.saveLogInAsync(logModel);
		//DbLogManager.savaLog(logModel);
		
		//2016/01/26 add by robert
		currentModule.saveDbLog(logModel);
	}
	
	/**
	 * 送使用道具的任務判斷
	 */
	private void sendMissionCheck(){
		MoneyChangeParam param = (MoneyChangeParam) dataInfo.getData();
		if (param.getResult() != ErrorCode.SUCCESS) {
			return;
		}
		
		if(GainRateSystem.isAffectGame(param.getGameId())){
			if(!GainRateSystem.isCanDoMission(param.getGameId(), param.getGameHallId(), param.getGainRate())){
				return;
			}
		}
		
		//如果是下注
		if(param.getChangeWay() != null && param.getChangeWay().isDailyBet()){
			
			GameDropItemParam dropItemParam = param.getDropItemParam();
			
			if(dropItemParam == null)
				return;
		}
	}
}
